﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EFFC.Net.Interface;
using EFFC.Net.Parameters;
using System.IO;
using System.Drawing;
using System.Drawing.Printing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using Word = Microsoft.Office.Interop.Word;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
using EFFC.Net.Returns;
using System.Threading;
using System.Diagnostics;
using System.Collections;
using EFFC.Net.Common;
using PDFPrintTool;
using EFFC.Net.ResourceLib.Parameters;
using EFFC.Net.ResourceLib.Returns;
using Microsoft.Office.Interop.Excel;

namespace EFFC.Net.ResourceLib.Print
{
    /// <summary>
    /// 文件列印工具類
    /// </summary>
    public class PrintAccess : IDisposable, IResourceEntity
    {
        /// <summary>
        ///  釋放Excel資源
        /// </summary>
        /// <param name="hwnd"></param>
        /// <param name="ID"></param>
        /// <returns></returns>
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        private static extern int GetWindowThreadProcessId(IntPtr hwnd, out   int ID);
        public static void ReleaseExcelProcess(Application excelObj)
        {
            IntPtr t = new IntPtr(excelObj.Hwnd);
            int k = 0;
            GetWindowThreadProcessId(t, out   k);
            System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById(k);
            p.Kill();
        }


        string _id = string.Empty;
        string _tmpPath = string.Empty;
        PrintDocument printDocument;
        Word.Application wordApp;
        Word.Document wordDoc;
        Excel.Application excelApp;
        Excel.Workbook excelBook;

        public string ID
        {
            get
            {
                if (_id == "")
                {
                    _id = "PrintAccess" + Guid.NewGuid().ToString();
                }

                return _id;
            }
        }

        /// <summary>
        /// 釋放資源
        /// </summary>
        public void Release()
        {

            try
            {
                object saveChange = Word.WdSaveOptions.wdDoNotSaveChanges;
                object oMissing = Type.Missing;

                if (wordDoc != null)
                {
                    wordDoc.Close(saveChange, oMissing, oMissing);
                    Marshal.ReleaseComObject(wordDoc);
                    wordDoc = null;
                }

                if (wordApp != null)
                {
                    while (wordApp.BackgroundPrintingStatus > 0)
                    {
                        System.Threading.Thread.Sleep(250);
                    }
                    wordApp.Quit(saveChange, oMissing, oMissing);
                    Marshal.ReleaseComObject(wordApp);
                    wordApp = null;
                }

                if (excelBook != null)
                {
                    excelBook.Close(saveChange, oMissing, oMissing);
                    excelBook = null;
                }
                if (excelApp != null)
                {
                    excelApp.Quit();
                    ReleaseExcelProcess(excelApp);
                    excelApp = null;
                }

                if (printDocument != null)
                    printDocument = null;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public void Dispose()
        {
            Release();
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// 列印執行統一入口方法
        /// </summary>
        /// <param name="p">PrintParameter參數</param>
        /// <returns>PrintRtn</returns>
        public PrintRtn PrintProcess(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                PrintFileCollection wordColl = new PrintFileCollection();
                PrintFileCollection excelColl = new PrintFileCollection();
                PrintFileCollection pdfColl = new PrintFileCollection();
                PrintFileCollection tifColl = new PrintFileCollection();
                PrintFileCollection txtColl = new PrintFileCollection();
                PrintFileCollection imgColl = new PrintFileCollection();

                foreach (FileInfo file in p.PrintFiles)
                {
                    string exter = file.Extension.ToUpper();

                    if (exter == ".DOC" || exter == ".DOCX") wordColl.Add(file);

                    if (exter == ".XLS" || exter == ".XLSX") excelColl.Add(file);

                    if (exter == ".PDF") pdfColl.Add(file);

                    if (exter == ".TIF" || exter == ".TIFF") tifColl.Add(file);

                    if (exter == ".TXT") txtColl.Add(file);

                    if (exter == ".JPG" || exter == ".JPEG" || exter == ".GIF" || exter == ".BMP" || exter == ".PNG")
                        imgColl.Add(file);

                }

                //如果有word檔需要列印
                if (wordColl.Count > 0)
                {
                    p.PrintFiles = wordColl;
                    //Thread th = new Thread(new ThreadStart(delegate() {
                    rtn = this.PrintWordByCom(p);
                    //}));
                    //th.Start();
                }

                //如果有excel檔需要列印
                if (excelColl.Count != 0)
                {
                    p.PrintFiles = excelColl;
                    rtn = this.PrintExcelByCom(p);
                }
                //如果有tif檔需要列印
                if (tifColl.Count != 0)
                {
                    p.PrintFiles = tifColl;
                    rtn = this.PrintTif(p);
                }

                //如果有pdf檔需要列印
                if (pdfColl.Count != 0)
                {
                    p.PrintFiles = pdfColl;
                    rtn = this.PrintPDF(p);
                    //rtn = this.PrintPDFByProcess(p);調用pdf軟件用process物件執行列印
                }

                //如果有txt檔需要列印
                if (txtColl.Count != 0)
                {
                    p.PrintFiles = txtColl;
                    rtn = this.PrintTxt(p);
                }
                //如果有图片需要列印
                if (imgColl.Count != 0)
                {
                    p.PrintFiles = imgColl;
                    rtn = this.PrintImage(p);
                }
                //如果有字符串需要列印
                if (!string.IsNullOrEmpty(p.PrintString))
                {
                    rtn = this.PrintString(p);
                }

                //如果有有標籤需要列印
                if (p.PrintLabelList.Count > 0 && p.PrintLabelTemplate != "")
                {
                    rtn = PrintLabelString(p);
                }

            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
            }
            return rtn;

        }

        #region  Print doc Document
        /// <summary>
        /// 設置臨時列印機
        /// </summary>
        /// <param name="printerName"></param>
        private void setTempPrinter(string printerName)
        {
            string PreferrendPrinter = printerName;
            object[] oWordDialogParams = { PreferrendPrinter, true };
            object[] oWordDialogParamsWithPort = { string.Format("{0} on {1}", PreferrendPrinter, "NE02:"), true };
            string[] argNames = { "Printer", "DoNotSetAsSysDefault" };

            Word.Dialog printDialog = wordApp.Application.Dialogs[Word.WdWordDialog.wdDialogFilePrintSetup];
            object wordBasic = wordApp.Application.WordBasic;
            try
            {
                wordBasic.GetType().InvokeMember("FilePrintSetup", BindingFlags.InvokeMethod, null
                                                , wordBasic, oWordDialogParams, null, null, argNames);
            }
            catch
            {
                try
                {
                    wordBasic.GetType().InvokeMember("FilePrintSetup", BindingFlags.InvokeMethod, null
                                            , wordBasic, oWordDialogParamsWithPort, null, null, argNames);
                }
                catch
                {
                    throw;
                }
            }
        }
        /// <summary>
        /// 調用Com組件直接列印Word檔
        /// </summary>
        /// <param name="fileName">PrintParameter</param>
        /// <returns>PrintRtn</returns>
        private PrintRtn PrintWordByCom(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                wordApp = new Word.Application(); ;
                wordApp.Visible = false;
                wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
                object oMissing = Type.Missing;

                setTempPrinter(p.PrinterName);

                foreach (FileInfo fileInfo in p.PrintFiles)
                {
                    wordDoc = wordApp.Documents.Open(fileInfo.FullName,
                                ref oMissing, ref oMissing, ref oMissing,
                                ref oMissing, ref oMissing, ref oMissing,
                                ref oMissing, ref oMissing, ref oMissing,
                                ref oMissing, ref oMissing, ref oMissing,
                                ref oMissing, ref oMissing, ref oMissing);

                    wordDoc.PrintOut(true, ref oMissing, ref oMissing,
                                ref oMissing, ref oMissing, ref oMissing,
                                ref oMissing, ref oMissing, ref oMissing,
                                ref oMissing, ref oMissing, ref oMissing,
                                ref oMissing, ref oMissing, ref oMissing);

                    Thread.Sleep(p.PrintWaitTime);
                }
                rtn.IsSuccess = true;
            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
                throw;
            }
            finally
            {
                this.Dispose();
            }

            return rtn;
        }
        #endregion

        #region  Print xls Document
        /// <summary>
        /// 調用Com组件直接列印Excel檔
        /// </summary>
        /// <param name="fileName">PrintParameter</param>
        /// <returns>PrintRtn</returns>
        private PrintRtn PrintExcelByCom(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            excelApp = new Excel.Application();
            try
            {
                object varMissing = Type.Missing;
                excelApp.DisplayAlerts = false;

                foreach (FileInfo fileInfo in p.PrintFiles)
                {
                    excelBook = excelApp.Workbooks.Open(fileInfo.FullName,
                            varMissing, varMissing, varMissing, varMissing,
                            varMissing, varMissing, varMissing, varMissing,
                            varMissing, varMissing, varMissing, varMissing,
                            varMissing, varMissing);

                    Excel.Sheets wsheet = excelBook.Worksheets;

                    wsheet.PrintOutEx(varMissing, varMissing, varMissing, varMissing,
                                        p.PrinterName, varMissing, varMissing, varMissing,
                                        varMissing);

                    Thread.Sleep(p.PrintWaitTime);
                }
                rtn.IsSuccess = true;
            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
                throw;
            }
            finally
            {
                this.Dispose();
            }
            return rtn;
        }


        #endregion

        #region  Print Tif Document

        private Image m_Image;
        private Int32 m_CurrentPage;
        private Int32 m_PageCount;
        /// <summary>
        /// 列印Tif檔
        /// </summary>
        /// <param name="fileName">PrintParameter</param>
        /// <returns>PrintRtn</returns>
        private PrintRtn PrintTif(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                foreach (FileInfo fileInfo in p.PrintFiles)
                {
                    m_Image = Image.FromFile(fileInfo.FullName);
                    printDocument = new PrintDocument();
                    printDocument.PrinterSettings.PrinterName = p.PrinterName;
                    printDocument.BeginPrint += new PrintEventHandler(printDocument_BeginPrint);
                    printDocument.PrintPage += new PrintPageEventHandler(printDocument_PrintPage);
                    printDocument.Print();
                    Thread.Sleep(p.PrintWaitTime);
                }


                rtn.IsSuccess = true;
            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
            }
            finally
            {
                this.Dispose();
            }
            return rtn;
        }
        //計算列印的頁數
        private void printDocument_BeginPrint(object sender, PrintEventArgs e)
        {
            m_CurrentPage = 0;
            m_PageCount = m_Image.GetFrameCount(FrameDimension.Page);
        }
        //執行列印
        private void printDocument_PrintPage(object sender, PrintPageEventArgs e)
        {
            m_Image.SelectActiveFrame(FrameDimension.Page, m_CurrentPage);
            e.Graphics.DrawImage(m_Image, 0, 0);
            ++m_CurrentPage;
            e.HasMorePages = (m_CurrentPage < m_PageCount);
        }

        #endregion

        #region  Print String Document

        private string printString = string.Empty;

        /// <summary>
        /// 列印文字字符
        /// </summary>
        /// <param name="p">PrintParameter參數，其PrintString需有值</param>
        /// <returns>PrintRtn</returns>
        private PrintRtn PrintString(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                printString = p.PrintString;
                printDocument = new PrintDocument();
                printDocument.PrinterSettings.PrinterName = p.PrinterName;
                printDocument.PrintPage += new PrintPageEventHandler(PrintString_PrintPage);
                printDocument.Print();

                rtn.IsSuccess = true;
            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
            }
            finally
            {
                this.Dispose();
            }
            return rtn;
        }

        private void PrintString_PrintPage(object sender, PrintPageEventArgs ev)
        {
            System.Drawing.Font printFont = new System.Drawing.Font("宋體", 13);
            float yPos = 0;
            int count = 0;
            float leftMargin = ev.MarginBounds.Left;
            float topMargin = ev.MarginBounds.Top;

            yPos = topMargin + (count * printFont.GetHeight(ev.Graphics));
            ev.Graphics.DrawString(printString, printFont, Brushes.Black, leftMargin, yPos, new StringFormat());
        }
        #endregion

        #region Print Pdf Document

        private PrintRtn PrintPDF(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                PdfPrintTool tool = new PdfPrintTool();
                foreach (FileInfo fileInfo in p.PrintFiles)
                {
                    bool success = tool.PrintPDF(fileInfo.FullName, p.PrinterName);
                    if (success)
                        Thread.Sleep(p.PrintWaitTime);
                    else
                    {
                        rtn.IsSuccess = false;
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
            }
            return rtn;
        }

        private PrintRtn PrintPDFByProcess(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                Process objP = new Process();
                objP.StartInfo.CreateNoWindow = true;
                objP.StartInfo.UseShellExecute = true;
                objP.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

                foreach (FileInfo fileInfo in p.PrintFiles)
                {
                    if (fileInfo.Extension.ToUpper() == ".PDF")
                    {
                        try
                        {
                            //優先選擇adobe reader來列印
                            objP.StartInfo.FileName = "AcroRd32.exe";
                            objP.StartInfo.Arguments = " /t \"" + fileInfo.FullName + "\" \"" + p.PrinterName + "\"";
                        }
                        catch
                        {
                            //優先選擇adobe Acrobat來列印
                            objP.StartInfo.FileName = "Acrobat.exe";
                            objP.StartInfo.Arguments = " /t \"" + fileInfo.FullName + "\" \"" + p.PrinterName + "\"";
                        }
                    }
                    else
                    {
                        objP.StartInfo.FileName = fileInfo.Name;
                        objP.StartInfo.Verb = "print";
                    }

                    objP.Start();

                    Thread.Sleep(p.PrintWaitTime);
                }

                //所有的文檔列印完成后釋放資源
                //if(objP!=null)
                //    objP.Kill();

                rtn.IsSuccess = true;

            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
            }
            return rtn;
        }
        #endregion

        #region Process Txt Document
        private System.Drawing.Font printFont;
        private StreamReader streamToPrint;
        /// <summary>
        /// 列印txt檔
        /// </summary>
        /// <param name="p">PrintParameter參數</param>
        /// <returns></returns>
        private PrintRtn PrintTxt(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                foreach (FileInfo fileInfo in p.PrintFiles)
                {
                    streamToPrint = new StreamReader(fileInfo.FullName);
                    printFont = new System.Drawing.Font("Arial", 10);
                    PrintDocument pd = new PrintDocument();
                    pd.PrintPage += new PrintPageEventHandler(this.pd_PrintPage);
                    pd.Print();
                }

                rtn.IsSuccess = true;
            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
            }
            finally
            {
                streamToPrint.Close();
            }
            return rtn;
        }

        private void pd_PrintPage(object sender, PrintPageEventArgs ev)
        {
            float linesPerPage = 0;
            float yPos = 0;
            int count = 0;
            float leftMargin = ev.MarginBounds.Left;
            float topMargin = ev.MarginBounds.Top;
            string line = null;

            // 計算一頁的行數
            linesPerPage = ev.MarginBounds.Height /
               printFont.GetHeight(ev.Graphics);

            // 列印每一行的文字
            while (count < linesPerPage && ((line = streamToPrint.ReadLine()) != null))
            {
                yPos = topMargin + (count * printFont.GetHeight(ev.Graphics));
                ev.Graphics.DrawString(line, printFont, Brushes.Black, leftMargin, yPos, new StringFormat());
                count++;
            }

            // 如果大於一頁，則列印另一張紙
            if (line != null)
                ev.HasMorePages = true;
            else
                ev.HasMorePages = false;
        }
        #endregion

        #region Process Image Document
        /// <summary>
        /// 列印image檔
        /// </summary>
        /// <param name="p">PrintParameter參數</param>
        /// <returns></returns>
        private PrintRtn PrintImage(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                Process objP = new Process();
                objP.StartInfo.CreateNoWindow = true;
                objP.StartInfo.UseShellExecute = true;
                objP.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

                foreach (FileInfo fileInfo in p.PrintFiles)
                {
                    objP.StartInfo.FileName = "mspaint.exe";
                    objP.StartInfo.Arguments = " /pt \"" + fileInfo.FullName + "\" \"" + p.PrinterName + "\"";
                    objP.Start();

                    Thread.Sleep(p.PrintWaitTime);
                }

                rtn.IsSuccess = true;
            }
            catch (Exception ex)
            {
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
            }
            finally
            {
                streamToPrint.Close();
            }
            return rtn;
        }
        #endregion

        #region 标签列印
        private PrintRtn PrintLabelString(PrintParameter p)
        {
            PrintRtn rtn = new PrintRtn();
            try
            {
                //計算需要多少頁
                int totalPage = (p.PrintLabelList.Count() / p.PrintLabelRecordSize) + (((p.PrintLabelList.Count() % p.PrintLabelRecordSize) != 0) ? 1 : 0);

                //初始化labelprint的页数，有多少页，就有多少个labelprint参数集合
                ArrayList paralist = new ArrayList();
                for (int i = 0; i < totalPage; i++)
                {
                    paralist.Add(new List<string>());
                }

                //往labelprint参数集合中插入值，一个页面只能有PrintLabelRecordSize条数
                int index = 0;
                foreach (string s in p.PrintLabelList)
                {
                    List<string> tmpList = (List<string>)paralist[index];
                    if (tmpList.Count() < p.PrintLabelRecordSize)
                    {
                        tmpList.Add(s);
                        if (tmpList.Count == p.PrintLabelRecordSize)
                        {
                            index += 1;
                        }
                    }
                }

                //有多页就分多少次列印
                foreach (List<string> pList in paralist)
                {
                    rtn.IsSuccess = PrintLabelOnePage(p.PrinterName, p.PrintLabelTemplate, p.PrintLabelField, pList, p.PrintWaitTime);
                }

            }
            catch (Exception ex)
            {
                //將異常rtn結果返回給上層函數進行處理
                rtn.ErrorMessage = ex.Message;
                rtn.IsSuccess = false;
            }
            finally
            {
                this.Dispose();
            }

            return rtn;
        }

        /// <summary>
        /// 列印一頁標籤
        /// </summary>
        /// <param name="printerName">列印機名稱</param>
        /// <param name="template">模板文件路徑</param>
        /// <param name="labelList">要列印的標籤集合</param>
        /// <returns></returns>
        private bool PrintLabelOnePage(string printerName, string template, List<string> fieldList, List<string> labelList, int waitTime)
        {
            bool isSuccess = false;
            try
            {
                if (CreateWordDocument(template, ref wordDoc, ref wordApp))
                {
                    List<string> labStrList = labelList;
                    int index = -1;
                    int ListIndex = -1;
                    object oMissing = Type.Missing;
                    foreach (Word.Field myMergeField in wordDoc.Fields)
                    {
                        index++;
                        if (index % fieldList.Count() == 0)
                        {
                            ListIndex += 1;
                        }

                        Word.Range rngFieldCode = myMergeField.Code;
                        String fieldText = rngFieldCode.Text;

                        if (fieldText.Contains("MERGEFIELD"))
                        {
                            if (ListIndex < labStrList.Count)
                            {

                                Int32 endMerge = fieldText.IndexOf("\\");
                                Int32 fieldNameLength = fieldText.Length - endMerge;
                                String fieldName = fieldText.Substring(11, endMerge - 11).Trim();

                                for (int i = 0; i < fieldList.Count(); i++)
                                {
                                    string fieldValue = labStrList[ListIndex].Split('|')[i];
                                    if (fieldName == fieldList[i])
                                    {
                                        myMergeField.Select();
                                        wordApp.Selection.TypeText(fieldValue);
                                    }
                                }
                            }
                            else
                            {
                                myMergeField.Select();
                                wordApp.Selection.TypeText(" ");
                            }
                        }
                    }

                    setTempPrinter(printerName);

                    wordDoc.PrintOut(true, ref oMissing, ref oMissing,
                                    ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                                    ref oMissing, ref oMissing, ref oMissing, ref oMissing,
                                    ref oMissing, ref oMissing, ref oMissing, ref oMissing);

                    Thread.Sleep(waitTime);

                    isSuccess = true;
                }
            }
            catch
            {
                isSuccess = false;
                throw;
            }
            finally
            {
                this.Dispose();
            }
            return isSuccess;
        }

        /// <summary> 
        /// 從模板創建新的Word文档
        /// </summary> 
        /// <param name="templateName">模板文件名（含路徑）</param> 
        /// <param name="wDoc">返回的Word.Document对象</param> 
        /// <param name="WApp">返回的Word.Application对象</param> 
        /// <returns></returns> 
        public bool CreateWordDocument(string templateName, ref Word.Document wDoc, ref Word.Application WApp)
        {
            Word.Document thisDocument = null;
            Word.Application thisApplication = new Word.Application();
            thisApplication.Visible = false;
            thisApplication.Caption = "";
            thisApplication.Options.CheckSpellingAsYouType = false;
            thisApplication.Options.CheckGrammarAsYouType = false;

            Object Template = templateName;// Optional Object. The name of the template to be used for the new document. If this argument is omitted, the Normal template is used. 
            Object NewTemplate = false;// Optional Object. True to open the document as a template. The default value is False. 
            Object DocumentType = Word.WdNewDocumentType.wdNewBlankDocument; // Optional Object. Can be one of the following WdNewDocumentType constants: wdNewBlankDocument, wdNewEmailMessage, wdNewFrameset, or wdNewWebPage. The default constant is wdNewBlankDocument. 
            Object Visible = true;//Optional Object. True to open the document in a visible window. If this value is False, Microsoft Word opens the document but sets the Visible property of the document window to False. The default value is True. 

            try
            {
                Word.Document wordDoc = thisApplication.Documents.Add(ref Template, ref NewTemplate, ref DocumentType, ref Visible);
                thisDocument = wordDoc;
                wDoc = wordDoc;
                WApp = thisApplication;
                return true;
            }
            catch (Exception ex)
            {
                string err = string.Format("創建臨時Word檔出错，錯誤原因：{0}", ex.Message);
                throw new Exception(err, ex);
            }
        }

        #endregion

        #region 設置默認列印機
        /// <summary>
        /// 設置默認列印機
        /// </summary>
        /// <param name="PrinterName">列印機名稱</param>
        /// <returns>true:成功；false：失敗</returns>
        [DllImport("winspool.drv", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool SetDefaultPrinter(string PrinterName);
        #endregion



    }
}
